using System;
using System.Collections.Generic;
using System.Text;
using Barrage.Global;

namespace Barrage.Shaders
{
    /// <summary>
    /// Implements a singleton shader cache with autoload functions
    /// </summary>
    public class ShaderManager : IDisposable
    {
        private static ShaderManager instance = null;

        /// <summary>
        /// Returns the class instance.
        /// </summary>
        public static ShaderManager Shaders { get { if (instance == null) instance = new ShaderManager(); return instance; } }

        private ShaderManager()
        {
            createDefaultShader();
            Engine.RegisterDisposeHandler(new EngineDisposeHandler(Dispose));
        }
        private Dictionary<string, Shader> shaders = new Dictionary<string, Shader>();

        private Shader defaultShader;
        /// <summary>
        /// Returns the default shader (BaseShader instance) that's loaded when loaded shaders return error
        /// </summary>
        public static Shader DefaultShader { get { return instance.defaultShader; } }

        void createDefaultShader()
        {
            defaultShader = BaseShader.Instance;
        }

        /// <summary>
        /// Tries to load the shader with the specified name (in the ShaderPath folder)
        /// </summary>
        /// <param name="name">shader name</param>
        /// <returns>If everything went well, the loaded shader. Else, the default shader</returns>
        public Shader this[string name]
        {
            get
            {
                Shader s = null;
                if (shaders.TryGetValue(name, out s))
                    return s;
                NLog.LogManager.GetLogger(ToString()).Warn("Shader " + name + " not found. Trying to load");
                try
                {
                    s = new D3DShader(name);
                    NLog.LogManager.GetLogger(ToString()).Debug("Shader " + name + " finished loading.");
                }
                catch
                {
                    NLog.LogManager.GetLogger(ToString()).Error("Error loading shader " + name);
                    s = DefaultShader;
                }
                shaders.Add(name, s);
                return s;
            }
        }

        /// <summary>
        /// Clear resources
        /// </summary>
        public void Dispose()
        {
            foreach (Shader s in shaders.Values)
                if (s != defaultShader)
                    s.Dispose();

            defaultShader = null;
            shaders.Clear();
            instance = null;
            NLog.LogManager.GetLogger(ToString()).Debug("Disposing");
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Destructor.Clear resources
        /// </summary>
        ~ShaderManager()
        {
            Dispose();
        }
    }

}
